/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import { RequestOptionsInit, ResponseError, extend } from 'umi-request';
import { notification, message } from 'antd';
import { history } from 'umi';
import { stringify } from 'qs';
import { guid } from './commons';
import { userStoarge } from './Storage';
import { getToken, deleteButtons, deleteRoutes } from './authority';

/**
 * 自定义错误
 */
interface OaBusiError {
  success: boolean;
  errorCode?: string;
  errorMsg?: string;
}

const codeMessage = {
  200: '服务器成功返回请求的数据。',
  201: '新建或修改数据成功。',
  202: '一个请求已经进入后台排队（异步任务）。',
  204: '删除数据成功。',
  400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
  401: '用户没有权限（令牌、用户名、密码错误）。',
  403: '用户得到授权，但是访问是被禁止的。',
  404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
  406: '请求的格式不可得。',
  410: '请求的资源被永久删除，且不会再得到的。',
  422: '当创建一个对象时，发生一个验证错误。',
  500: '服务器发生错误，请检查服务器。',
  502: '网关错误。',
  503: '服务不可用，服务器暂时过载或维护。',
  504: '网关超时。',
};

const noLoginMessage = {
  'E0054': '请先登录，在进行相关操作',
  'E0055': 'Token验证失败，请重新登录',
  'E0056': 'Token已失效，请重新登录'
}

/**
 * 异常处理程序
 */
const errorHandler = (error: ResponseError): OaBusiError => {
  console.info(error);
  // console.info(response);
  const errorCode = error['errorCode'];
  const selfError: OaBusiError = {
    success: false
  }
  if (errorCode) {
    const errorMsg = error['errorMsg'];
    selfError.errorCode = errorCode;
    selfError.errorMsg = errorMsg;
    // 错误码为未登录或者token失效等，跳转到登录页面
    const errorMsg1 = noLoginMessage[errorCode];
    if (errorMsg1) {
      // 多个请求同时发起时，判断是否有请求已提示失效
      const tokenInvalid = userStoarge.getItem('token-invalid');
      if (tokenInvalid === '1') {
        return selfError;
      }
      userStoarge.setItem('token-invalid', '1');
      // message.warning(msg);
      console.info(window.location);
      console.info(window.location.href);
      console.info(window.location.pathname);
      // const pathName = window.location.pathname;
      // 登录失效了，先删菜单及按钮数据
      deleteRoutes();
      deleteButtons();
      history.replace({
        pathname: '/user/login',
        search: stringify({
          // 记录从那个页面跳转跳转到登录页面的，登录后在跳转回去
          redirect: window.location.href
        })
      });
    } else {
      message.error(`${errorCode}:${errorMsg}`);
    }
  } else {
    // 没有errorCode，表示非业务失败
    selfError.errorCode = 'E9999';
    let errorMsgEx: string = '系统异常';
    if (error && error['status']) {
      const errorText = codeMessage[error["status"]] || error["message"];
      errorMsgEx = `${errorMsgEx}，${errorText}`;
      const url = error["path"];
      notification.error({
        message: '请求错误 ' + error["status"]+ `: ${url}`,
        description: errorText,
      });
    }
    selfError.errorMsg = errorMsgEx;
  }
  console.info(selfError);
  return selfError;
};

/**
 * 配置request请求时的默认参数
 */
const request = extend({
  errorHandler, // 默认错误处理
  credentials: 'include', // 默认请求是否带上cookie
});

/**
 * 请求时，报文头添加token和随机数，方便前后端查询问题
 */
request.interceptors.request.use((url: string, options: RequestOptionsInit) => {
  const rnd = guid();
  // 获取存储在本地的token
  const token = getToken();
  const { headers = {} } = options || {};
  const tokenHeaders = {
    guid: rnd,
    token,
    ...headers
  }
  if (token) {
    // console.info(`token: ${token}`);
    return {
      url,
      options: {
        ...options,
        headers: {
          ...tokenHeaders
        }
      }
    }
  }
  return {
    url,
    options: {
      ...options
    }
  }
});

/**
 * 响应时，统一拦截
 */
request.interceptors.response.use(async (response) => {
  console.info(response);
  const data = await response.clone().json();
  console.info(data);
  // 通过success来判断是否请求成功，具体情况看个人项目
  if (data && data.success) {
    userStoarge.removeItem('token-invalid');
    return response;
  }
  // 注意：需要reject出去才会在请求不成功或返回错误的code时调用errorHandler
  return Promise.reject(data);
});

export default request;